/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pnt.server;

import java.net.InetSocketAddress;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;


/**
 * Will possible be extended at a later date to use persistent storage.
 * 
 * @author andrew
 */

        
public class Registry {
    
    private static Logger logger = Logger.getLogger("pnt.client"); 
 
    static Map<String,Node> byName;
    static Map<InetSocketAddress,Node> byEndpoint;

    // TODO: Add database support, as opposed to hashing... in theory, we could
    //       have multiple registrations for the same name (i.e. diff applications)
    public static void addNode(Node n){
        
        logger.info("Adding node " + n.name);
        
        if (byName == null || byEndpoint == null){
            byName = new HashMap<String,Node>(10);
            byEndpoint = new HashMap<InetSocketAddress,Node>(10);
        }

        byName.put(n.name, n);

        for(Node.Instance i : n.instances){
            if (i.ext_NATExtEndpoint != null)
                byEndpoint.put(i.ext_NATExtEndpoint, n);
                
            if (i.ext_NativeEndpoint != null)
                byEndpoint.put(i.ext_NativeEndpoint, n);
                
            if (i.ext_SNPNTEndpoint != null)
                byEndpoint.put(i.ext_SNPNTEndpoint, n);
                
            if (i.ext_SNRelayEndpoint != null)
                byEndpoint.put(i.ext_SNRelayEndpoint, n);
        }
    }
    
    // TODO: Make this return a node array
    public static Node getNode(String name){
        return byName.get(name);
    }
    
    // TODO: Make this return a node array
    public static Node getNode(InetSocketAddress endpoint){
        return byEndpoint.get(endpoint);
    }
    
    public static boolean deleteNode(String name){
        
        logger.info("Deleting node " + name);
        
        if (byName == null || byEndpoint == null){
            return false;
        }
        
        Node n = byName.get(name);
        
        if (n == null){
            logger.warning("Could not find node.");
            return false;
        }

        byName.remove(name);
        
        for(Node.Instance i : n.instances){
            if (i.ext_NATExtEndpoint != null)
                if(byEndpoint.remove(i.ext_NATExtEndpoint) == null) 
                    logger.warning("ext_NATExtEndpoint mapping value not found. Could not remove.");
                
            if (i.ext_NativeEndpoint != null)
                if(byEndpoint.remove(i.ext_NativeEndpoint) == null)
                    logger.warning("ext_NativeEndpoint mapping value not found. Could not remove.");
                
            if (i.ext_SNPNTEndpoint != null)
                if(byEndpoint.remove(i.ext_SNPNTEndpoint) == null)
                    logger.warning("ext_SNPNTEndpoint mapping value not found. Could not remove.");
                
            if (i.ext_SNRelayEndpoint != null)
                if(byEndpoint.remove(i.ext_SNRelayEndpoint) == null)
                    logger.warning("ext_SNRelayEndpoint mapping value not found. Could not remove.");
        }
        
        return true;
    }
    
    /**
     * If only java had structs...
     */
    public static class Node{
        public boolean userAuthRequired;
        /**
         * 0 = Any
         * 1 = Registered-Users
         * 2 = Authenticated-Users
         * 3 = Registered-by-Self
         */
        public int authorisation;
        public String[] registeredWith;
        public String name;
        public String application;
        
        public Instance[] instances;
        
        public int expires;
        public Date created;
        
        public Node(String name, String application, Instance[] instances){
            this.name = name;
            this.application = application;
            this.instances = instances;
        }
        
        public static class Instance {
            public int number;
            public InetSocketAddress pvtEndpoint;
            /**
             * 0 = NoNAT
             * 1 = ConeNAT
             * 2 = SymmNAT
             */
            public int natType;
            
            public InetSocketAddress ext_NativeEndpoint;
            public InetSocketAddress ext_NATExtEndpoint;
            public InetSocketAddress ext_SNPNTEndpoint;
            public InetSocketAddress ext_SNRelayEndpoint;
            
        }
    }
}
